package gnss

import (
	"dgo/goutils/utils"
	"time"
)

type IgsSSRHead struct {
	MsgID   uint16
	NaviSys byte
	GPSTime time.Time
	UpIntv  int // s

	/**
	Indicator for transmitting messages
	with the same IGS Message
	Number and SSR Epoch Time:
	 0 – last message of a sequence
	 1 – multiple message transmitted
	*/
	SyncFlag byte // Multiple Message Indicator
	Refd     byte // Satellite Reference Datum

	IOD    byte
	ProvID uint16
	SolID  byte

	Indicator1 byte
	Indicator2 byte
}

func (this *IgsSSRHead) EncodeSSR4Head(bb *utils.BytesBuilder, startByteN int, subtype int, satn uint32) int {
	startBitN := 0
	// head = 79
	bb.CheckSize(startByteN, 10)

	//msg type
	bb.SetBitU16(startByteN, startBitN, 12, this.MsgID)
	startBitN += 12

	// version
	bb.SetBitU8(startByteN, startBitN, 3, 1)
	startBitN += 3

	// subtype
	bb.SetBitU8(startByteN, startBitN, 8, byte(subtype))
	startBitN += 8

	// GPS Epoch Time 1s
	_, tow := Time2GpsT(this.GPSTime)
	epoch := RoundU(tow) % 604800
	bb.SetBitU32(startByteN, startBitN, 20, uint32(epoch))
	startBitN += 20

	/* update interval */
	var idx = 0
	for i := 0; i < 15; i++ {
		if SSR_UP_INTV[i] >= this.UpIntv {
			idx = i
			break
		}
	}
	bb.SetBitU8(startByteN, startBitN, 4, byte(idx))
	startBitN += 4

	/** multiple message indicator */
	bb.SetBitU8(startByteN, startBitN, 1, byte(this.SyncFlag))
	startBitN += 1

	bb.SetBitU8(startByteN, startBitN, 4, byte(this.IOD))
	startBitN += 4 /* IOD SSR */

	bb.SetBitU32(startByteN, startBitN, 16, uint32(this.ProvID))
	startBitN += 16 /* provider ID */

	bb.SetBitU32(startByteN, startBitN, 4, uint32(this.SolID))
	startBitN += 4 /* solution ID */

	/* satellite ref datum */
	bb.SetBitU8(startByteN, startBitN, 1, byte(this.Refd))
	startBitN += 1

	bb.SetBitU32(startByteN, startBitN, 6, satn)
	startBitN += 6
	return startBitN
}

func (this *IgsSSRHead) EncodeSSR3Head(bb *utils.BytesBuilder, startByteN int, subtype int, satn uint32) int {
	startBitN := 0
	// head = 78
	bb.CheckSize(startByteN, 10)

	//msg type
	bb.SetBitU16(startByteN, startBitN, 12, this.MsgID)
	startBitN += 12

	// version
	bb.SetBitU8(startByteN, startBitN, 3, 1)
	startBitN += 3

	// subtype
	bb.SetBitU8(startByteN, startBitN, 8, byte(subtype))
	startBitN += 8

	// GPS Epoch Time 1s
	_, tow := Time2GpsT(this.GPSTime)
	epoch := RoundU(tow) % 604800
	bb.SetBitU32(startByteN, startBitN, 20, uint32(epoch))
	startBitN += 20

	/* update interval */
	var idx = 0
	for i := 0; i < 15; i++ {
		if SSR_UP_INTV[i] >= this.UpIntv {
			idx = i
			break
		}
	}
	bb.SetBitU8(startByteN, startBitN, 4, byte(idx))
	startBitN += 4

	/** multiple message indicator */
	bb.SetBitU8(startByteN, startBitN, 1, byte(this.SyncFlag))
	startBitN += 1

	bb.SetBitU8(startByteN, startBitN, 4, byte(this.IOD))
	startBitN += 4 /* IOD SSR */

	bb.SetBitU32(startByteN, startBitN, 16, uint32(this.ProvID))
	startBitN += 16 /* provider ID */

	bb.SetBitU32(startByteN, startBitN, 4, uint32(this.SolID))
	startBitN += 4 /* solution ID */

	bb.SetBitU32(startByteN, startBitN, 6, satn)
	startBitN += 6
	return startBitN
}

func (this *IgsSSRHead) EncodeSSR7Head(bb *utils.BytesBuilder, startByteN int, subtype int, satn uint32) int {
	startBitN := 0
	// head = 80
	bb.CheckSize(startByteN, 10)

	//msg type
	bb.SetBitU16(startByteN, startBitN, 12, this.MsgID)
	startBitN += 12

	// version
	bb.SetBitU8(startByteN, startBitN, 3, 1)
	startBitN += 3

	// subtype
	bb.SetBitU8(startByteN, startBitN, 8, byte(subtype))
	startBitN += 8

	// GPS Epoch Time 1s
	_, tow := Time2GpsT(this.GPSTime)
	epoch := RoundU(tow) % 604800
	bb.SetBitU32(startByteN, startBitN, 20, uint32(epoch))
	startBitN += 20

	/* update interval */
	var idx = 0
	for i := 0; i < 15; i++ {
		if SSR_UP_INTV[i] >= this.UpIntv {
			idx = i
			break
		}
	}
	bb.SetBitU8(startByteN, startBitN, 4, byte(idx))
	startBitN += 4

	/** multiple message indicator */
	bb.SetBitU8(startByteN, startBitN, 1, byte(this.SyncFlag))
	startBitN += 1

	bb.SetBitU8(startByteN, startBitN, 4, byte(this.IOD))
	startBitN += 4 /* IOD SSR */

	bb.SetBitU32(startByteN, startBitN, 16, uint32(this.ProvID))
	startBitN += 16 /* provider ID */

	bb.SetBitU32(startByteN, startBitN, 4, uint32(this.SolID))
	startBitN += 4 /* solution ID */

	/** Dispersive Bias Consistency	Indicator */
	bb.SetBitU8(startByteN, startBitN, 1, byte(this.Indicator1))
	startBitN += 1

	/** MW Consistency Indicator */
	bb.SetBitU8(startByteN, startBitN, 1, byte(this.Indicator2))
	startBitN += 1

	bb.SetBitU32(startByteN, startBitN, 6, satn)
	startBitN += 6
	return startBitN
}

func (this *IgsSSRHead) EncodeIGM04Head(bb *utils.BytesBuilder, startByteN int, subtype int, satn uint32) int {
	startBitN := 0
	// head = 80
	bb.CheckSize(startByteN, 10)

	//msg type
	bb.SetBitU16(startByteN, startBitN, 12, this.MsgID)
	startBitN += 12

	// version
	bb.SetBitU8(startByteN, startBitN, 3, 1)
	startBitN += 3

	// subtype
	bb.SetBitU8(startByteN, startBitN, 8, byte(subtype))
	startBitN += 8

	// GPS Epoch Time 1s
	_, tow := Time2GpsT(this.GPSTime)
	epoch := RoundU(tow) % 604800
	bb.SetBitU32(startByteN, startBitN, 20, uint32(epoch))
	startBitN += 20

	/* update interval */
	var idx = 0
	for i := 0; i < 15; i++ {
		if SSR_UP_INTV[i] >= this.UpIntv {
			idx = i
			break
		}
	}
	bb.SetBitU8(startByteN, startBitN, 4, byte(idx))
	startBitN += 4

	/** multiple message indicator */
	bb.SetBitU8(startByteN, startBitN, 1, byte(this.SyncFlag))
	startBitN += 1

	bb.SetBitU8(startByteN, startBitN, 4, byte(this.IOD))
	startBitN += 4 /* IOD SSR */

	bb.SetBitU32(startByteN, startBitN, 16, uint32(this.ProvID))
	startBitN += 16 /* provider ID */

	bb.SetBitU32(startByteN, startBitN, 4, uint32(this.SolID))
	startBitN += 4 /* solution ID */

	bb.SetBitU32(startByteN, startBitN, 6, satn)
	startBitN += 6
	return startBitN
}

/*
IGM04一致
*/
func (this *IgsSSRHead) EncodeIGM_IFPBHead(bb *utils.BytesBuilder, startByteN int, subtype int, satn uint32) int {
	startBitN := 0
	// head = 80
	bb.CheckSize(startByteN, 10)

	//msg type
	bb.SetBitU16(startByteN, startBitN, 12, this.MsgID)
	startBitN += 12

	// version
	bb.SetBitU8(startByteN, startBitN, 3, 1)
	startBitN += 3

	// subtype
	bb.SetBitU8(startByteN, startBitN, 8, byte(subtype))
	startBitN += 8

	// GPS Epoch Time 1s
	_, tow := Time2GpsT(this.GPSTime)
	epoch := RoundU(tow) % 604800
	bb.SetBitU32(startByteN, startBitN, 20, uint32(epoch))
	startBitN += 20

	/* update interval */
	var idx = 0
	for i := 0; i < 15; i++ {
		if SSR_UP_INTV[i] >= this.UpIntv {
			idx = i
			break
		}
	}
	bb.SetBitU8(startByteN, startBitN, 4, byte(idx))
	startBitN += 4

	/** multiple message indicator */
	bb.SetBitU8(startByteN, startBitN, 1, byte(this.SyncFlag))
	startBitN += 1

	bb.SetBitU8(startByteN, startBitN, 4, byte(this.IOD))
	startBitN += 4 /* IOD SSR */

	bb.SetBitU32(startByteN, startBitN, 16, uint32(this.ProvID))
	startBitN += 16 /* provider ID */

	bb.SetBitU32(startByteN, startBitN, 4, uint32(this.SolID))
	startBitN += 4 /* solution ID */

	bb.SetBitU32(startByteN, startBitN, 6, satn)
	startBitN += 6
	return startBitN
}
